package WGH;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeSet;
import cpsc433.Pair;
import cpsc433.PredicateReader;
import cpsc433.SisyphusPredicates;
import cpsc433.Predicate.ParamType;

public class Environment extends PredicateReader implements SisyphusPredicates{

	static Environment instance=null;
	public boolean fixedAssignments;
	public Solution currentSolution;

	public static PersonTable PT = new PersonTable();
	public static RoomTable RT = new RoomTable();
	public static ProjectTable PrjTable = new ProjectTable();
	public static GroupTable GT = new GroupTable();
	public static AssignmentTable AT = new AssignmentTable();
	
	public Environment(String name) {
		super(name);
	}

	public static Environment get() {
		if(instance==null)
			instance= new Environment("ENV");
		return instance;
	}

	public static void reset() {
		PT = new PersonTable();
		RT = new RoomTable();
		PrjTable = new ProjectTable();
		GT = new GroupTable();
		AT = new AssignmentTable();		
	}




	@Override
	public void a_person(String p) {
		PT.insert(p);	
	}

	@Override
	public boolean e_person(String p) {
		return PT.selectName(p);
	}

	@Override
	public void a_secretary(String p) {
		if(!e_person(p))
			a_person(p);
		PT.getPerson(p).setRole(ROLE.SECRETARY);		
	}

	@Override
	public boolean e_secretary(String p) {
		return PT.getPerson(p).getRole()==ROLE.SECRETARY;
	}

	@Override
	public void a_researcher(String p) {
		if(!e_person(p))
			a_person(p);
		PT.getPerson(p).setRole(ROLE.RESEARCHER);
	}

	@Override
	public boolean e_researcher(String p) {
		return PT.getPerson(p).getRole()==ROLE.RESEARCHER;
	}

	@Override
	public void a_manager(String p) {
		if(!e_person(p))
			a_person(p);
		PT.getPerson(p).setRole(ROLE.MANAGER);
	}

	@Override
	public boolean e_manager(String p) {
		return PT.getPerson(p).getRole()==ROLE.MANAGER;
	}

	@Override
	public void a_smoker(String p) {
		if(!e_person(p))
			a_person(p);
		PT.getPerson(p).setSmoker(true);
	}

	@Override
	public boolean e_smoker(String p) {
		return PT.getPerson(p).isSmoker();
	}

	@Override
	public void a_hacker(String p) {
		if(!e_person(p))
			a_person(p);
		PT.getPerson(p).setHacker(true);
	}

	@Override
	public boolean e_hacker(String p) {
		return PT.getPerson(p).isHacker();
	}

	@Override
	public void a_in_group(String p, String grp) {
		if(!e_person(p))
			a_person(p);
		if(!e_group(grp))
			a_group(grp);
		PT.getPerson(p).setGroup(GT.getGroup(grp));
	}
	public void a_group(String p, String grp) {
		a_in_group(p, grp);
	}
	@Override
	public boolean e_in_group(String p, String grp) {
		return PT.getPerson(p).getGroup().toString().equals(grp);
	}
	public boolean e_group(String p, String grp) {
		return e_in_group(p, grp);
	}

	@Override
	public void a_in_project(String p, String prj) {
		if(!e_person(p))
			a_person(p);
		if(!e_project(prj))
			a_project(prj);
		PT.getPerson(p).setProject(PrjTable.getProject(prj));
	}
	public void a_project(String p, String prj) {
		a_in_project(p,prj);
	}

	@Override
	public boolean e_in_project(String p, String prj) {
		return PT.getPerson(p).getProject().toString().equals(prj);
	}
	public boolean e_project(String p, String prj) {
		return e_in_project(p,prj);
	}
	@Override
	public void a_heads_group(String p, String grp) {
		if(!e_person(p))
			a_person(p);
		if(!e_group(grp))
			a_group(grp);
		GT.getGroup(grp).setGroupHead(PT.getPerson(p));
		PT.getPerson(p).setGroup(GT.getGroup(grp));
	}

	@Override
	public boolean e_heads_group(String p, String grp) {
		return GT.getGroup(grp).getGroupHead().toString().equals(p);
	}

	@Override
	public void a_heads_project(String p, String prj) {
		if(!e_person(p))
			a_person(p);
		if(!e_project(prj))
			a_project(prj);
		PrjTable.getProject(prj).setProjectHead(PT.getPerson(p));
		PT.getPerson(p).setProject(PrjTable.getProject(prj));
	}

	@Override
	public boolean e_heads_project(String p, String prj) {
		return PrjTable.getProject(prj).getProjectHead().toString().equals(p);
	}

	@Override
	public void a_works_with(String p, TreeSet<Pair<ParamType, Object>> p2s) {
		for (Pair<ParamType, Object> pair : p2s){
			assert(pair.getKey().equals(ParamType.STRING));
			a_works_with(p,(String)pair.getValue());
		}
	}

	@Override
	public boolean e_works_with(String p, TreeSet<Pair<ParamType, Object>> p2s) {
		for (Pair<ParamType, Object> pair : p2s){
			assert(pair.getKey().equals(ParamType.STRING));
			if(!e_works_with(p,(String)pair.getValue()))
				return false;
		}
		return true;
	}

	@Override
	public void a_works_with(String p, String p2) {
		if(!e_person(p))
			a_person(p);
		if(!e_person(p2))
			a_person(p2);
		PT.getPerson(p).WorkWith.add(PT.getPerson(p2));
		PT.getPerson(p2).WorkWith.add(PT.getPerson(p));		
	}

	@Override
	public boolean e_works_with(String p, String p2) {
		if(!e_person(p))
			return false;
		if(!e_person(p2))
			return false;
		
		return PT.getPerson(p).WorkWith.contains(PT.getPerson(p2));
	}

	@Override
	public void a_assign_to(String p, String room) throws Exception {
		if(!e_person(p))
			a_person(p);
		if(!e_room(room))
			a_room(room);
		AT.insert(PT.getPerson(p),RT.getRoom(room));

	}

	@Override
	public boolean e_assign_to(String p, String room) {
		if(!e_person(p))
			return false;
		if(!e_room(room))
			return false;
		return AT.selectName(PT.getPerson(p),RT.getRoom(room));
	}

	@Override
	public void a_room(String r) {
		RT.insert(r);
	}

	@Override
	public boolean e_room(String r) {
		return RT.selectName(r);
	}

	@Override
	public void a_close(String room, String room2) {
		if(!e_room(room))
			a_room(room);
		if(!e_room(room2))
			a_room(room2);
		RT.getRoom(room).CloseTo.add(RT.getRoom(room2));
		RT.getRoom(room2).CloseTo.add(RT.getRoom(room));
	}

	@Override
	public boolean e_close(String room, String room2) {
		if(!e_room(room))
			return false;
		if(!e_room(room2))
			return false;		
		return RT.getRoom(room).CloseTo.contains(RT.getRoom(room2));
	}

	@Override
	public void a_close(String room, TreeSet<Pair<ParamType, Object>> set) {
		for (Pair<ParamType, Object> pair : set){
			assert(pair.getKey().equals(ParamType.STRING));
			a_close(room,(String)pair.getValue());
		}

	}

	@Override
	public boolean e_close(String room, TreeSet<Pair<ParamType, Object>> set) {
		for (Pair<ParamType, Object> pair : set){
			assert(pair.getKey().equals(ParamType.STRING));
			if(!e_close(room,(String)pair.getValue()))
				return false;
		}
		return true;
	}

	@Override
	public void a_large_room(String r) {
		if(!e_room(r))
			a_room(r);
		RT.getRoom(r).setRoomSize(RoomSize.LARGEROOM);
	}

	@Override
	public boolean e_large_room(String r) {
		return RT.getRoom(r).getRoomSize()==RoomSize.LARGEROOM;
	}

	@Override
	public void a_medium_room(String r) {
		if(!e_room(r))
			a_room(r);
		RT.getRoom(r).setRoomSize(RoomSize.MEDIUMROOM);
	}

	@Override
	public boolean e_medium_room(String r) {
		return RT.getRoom(r).getRoomSize()==RoomSize.MEDIUMROOM;
	}

	@Override
	public void a_small_room(String r) {
		if(!e_room(r))
			a_room(r);
		RT.getRoom(r).setRoomSize(RoomSize.SMALLROOM);
	}

	@Override
	public boolean e_small_room(String r) {
		return RT.getRoom(r).getRoomSize()==RoomSize.SMALLROOM;
	}

	@Override
	public void a_group(String g) {
		GT.insert(g);
	}

	@Override
	public boolean e_group(String g) {
		return GT.selectName(g);
	}

	@Override
	public void a_project(String p) {
		PrjTable.insert(p);

	}

	@Override
	public boolean e_project(String p) {
		return PrjTable.selectName(p);
	}

	@Override
	public void a_large_project(String prj) {
		if(!e_project(prj))
			a_project(prj);
		PrjTable.getProject(prj).setLargeProject(true);

	}

	@Override
	public boolean e_large_project(String prj) {
		return PrjTable.getProject(prj).isLargeProject();
	}

	@Override
	public String toString(){
		System.out.println("Assignment Table: "+AT);
		System.out.println("Group Table: "+ GT);
		System.out.println("Project Table:"+ PrjTable);
		System.out.println("Person Table:"+ PT);
		System.out.println("Room Table:" + RT);
		return "";		
	}
	public void writeSolution(String outputFileName){
		String s;
		System.out.println("Generate output file: "+outputFileName);
		try{
			PrintWriter output = new PrintWriter(new FileWriter(outputFileName));
			
	        for (Entry<String, Person> entry : PT.getPT().entrySet()) {
	            Person p = entry.getValue();
	            s=p.toString();	           
	           System.out.println(s);
	            output.println(s);
	        }	        
	        for (Entry<String, Room> entry : RT.getRT().entrySet()) {
	            Room r= entry.getValue();
	            s=r.toString();
	            System.out.println(s);
	            output.println(s);
	        }	        
	        for (Entry<String, Group> entry : GT.getGT().entrySet()) {
	            Group g=entry.getValue();
	            s=g.toString();
	            System.out.println(s);
	            output.println(s);
	        }	        
	        for (Entry<String, Project> entry : PrjTable.getPrjTable().entrySet()) {
	        	Project p= entry.getValue();
	            s = p.toString();
	            
	            System.out.println(s);
	            output.println(s);
	        }
	        for (Map.Entry<Person,Room> entry : AT.getAT().entrySet()) {
	            s ="assign-to("+entry.getKey().getName() + ","+ entry.getValue().getName() + ")";
	            System.out.println(s);
	            output.println(s);
	        }
			output.close();		
		}
		catch (IOException ex){
			ex.printStackTrace();
		}
		
	}

}
